package org.wsiz.vro.web.component;

import static org.wsiz.vro.web.component.DatePickerHelper.normalize;

import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

import javax.faces.component.FacesComponent;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;

import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;

import org.wsiz.vro.web.converter.LocalDateConverter;
import org.wsiz.vro.web.converter.LocalDateTimeConverter;

/**
 * Java side of the 'datePicker' composite component. Inspired from http://weblogs.java.net/blog/cayhorstmann/archive/2010/01/30/composite-input-components-jsf
 * Support java.util.Date, joda LocalDate and joda LocalDateTime. 
 */
@FacesComponent("components.DatePicker")
public class DatePicker extends UIInput implements NamingContainer {

    @Override
    public String getFamily() {
        return "javax.faces.NamingContainer";
    }

    @Override
    public void encodeBegin(FacesContext context) throws IOException {
        UIInput year = findUIInput("year");
        UIInput month = findUIInput("month");
        UIInput day = findUIInput("day");
        UIInput hour = findUIInput("hour");
        UIInput min = findUIInput("minute");

        Converter converter = getConverter();

        if (converter instanceof LocalDateConverter) {
            LocalDate localDate = (LocalDate) getValue();

            if (localDate == null) {
                localDate = LocalDate.fromCalendarFields(Calendar.getInstance(TimeZone.getTimeZone("GMT")));
            }

            year.setValue(normalize(localDate.getYear()));
            month.setValue(normalize(localDate.getMonthOfYear()));
            day.setValue(normalize(localDate.getDayOfMonth()));
        } else if (converter instanceof LocalDateTimeConverter) {
            LocalDateTime localDateTime = (LocalDateTime) getValue();

            if (localDateTime == null) {
                localDateTime = LocalDateTime.fromCalendarFields(Calendar.getInstance(TimeZone.getTimeZone("GMT")));
            }

            year.setValue(normalize(localDateTime.getYear()));
            month.setValue(normalize(localDateTime.getMonthOfYear()));
            day.setValue(normalize(localDateTime.getDayOfMonth()));
            hour.setValue(normalize(localDateTime.getHourOfDay()));
            min.setValue(normalize(localDateTime.getMinuteOfHour()));
        } else {

            Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT"));

            Date date = (Date) getValue();
            if (date != null) {
                c.setTime(date);
            }

            if (year != null) {
                year.setValue(normalize(c.get(Calendar.YEAR)));
            }

            if (month != null) {
                month.setValue(normalize(c.get(Calendar.MONTH) + 1));
            }

            if (day != null) {
                day.setValue(normalize(c.get(Calendar.DAY_OF_MONTH)));
            }

            if (hour != null) {
                hour.setValue(normalize(c.get(Calendar.HOUR_OF_DAY)));
            }

            if (min != null) {
                min.setValue(normalize(c.get(Calendar.MINUTE)));
            }
        }

        super.encodeBegin(context);
    }

    @Override
    protected Object getConvertedValue(FacesContext context, Object newSubmittedValue) throws ConverterException {
        return getConverter().getAsObject(context, this, (String) newSubmittedValue);
    }

    /**
     * Construct submitted value as 'yyyy-MM-dd', 'yyyy-MM-dd HH:mm' or 'HH:mm' The returned string is used by getConvertedValue...
     */
    @Override
    public Object getSubmittedValue() {
        StringBuilder sb = new StringBuilder();

        UIInput year = findUIInput("year");
        UIInput month = findUIInput("month");
        UIInput day = findUIInput("day");
        UIInput hour = findUIInput("hour");
        UIInput minute = findUIInput("minute");

        if (year.isRendered() && month.isRendered() && day.isRendered()) {
            sb.append(year.getSubmittedValue());
            sb.append("-").append(month.getSubmittedValue());
            sb.append("-").append(day.getSubmittedValue());
            if (hour.isRendered() && minute.isRendered()) {
                sb.append(" ");
            }
        }

        if (hour.isRendered() && minute.isRendered()) {
            sb.append(hour.getSubmittedValue());
            sb.append(":").append(minute.getSubmittedValue());
        }

        return sb.toString();
    }

    final private UIInput findUIInput(String id) {
        return (UIInput) findComponent(id);
    }
}